package search;

import helpers.DateHelper;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.search.Document;
import com.google.appengine.api.search.Field;
import com.google.appengine.api.search.GetRequest;
import com.google.appengine.api.search.GetResponse;
import com.google.appengine.api.search.Index;
import com.google.appengine.api.search.IndexSpec;
import com.google.appengine.api.search.Query;
import com.google.appengine.api.search.Results;
import com.google.appengine.api.search.ScoredDocument;
import com.google.appengine.api.search.SearchServiceFactory;

import entities.ArticleSearch;

public class ArticleSearchEngine {
	
	private static Index INDEX = SearchServiceFactory.getSearchService()
	.getIndex(IndexSpec.newBuilder().setName("article"));
	
	private static final Logger log = Logger
			.getLogger(ArticleSearchEngine.class.getName());

	public static void index(ArticleSearch obj) {
		
		try {
			Document.Builder docBuilder = Document.newBuilder();
			objectToSearchDocument(docBuilder, obj);
			Document doc = docBuilder.build();
			INDEX.put(doc);
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
		}
		
	}
	
	public static void update(ArticleSearch obj) {

		remove(obj.getId());
		index(obj);
	}

	public static void updateSearchFirst(ArticleSearch obj) {
		remove(obj.getId());
		index(obj);
	}

	public static void remove(String id) {
		
		try {
			Query query = Query.newBuilder().build("id:\"" + id + "\"");
			Results<ScoredDocument> docResult = INDEX.search(query);
			if (docResult.getNumberFound() > 0) {
				for (ScoredDocument scoredDocument : docResult) {
					INDEX.delete(scoredDocument.getId());
				}
			}
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
		}
	}

	public static void removeAllDocument() {
		
		int count = 0;
		while (true) {
			List<String> docIds = new ArrayList<String>();
			// Return a set of document IDs.
			GetRequest request = GetRequest.newBuilder()
					.setReturningIdsOnly(true).build();
			GetResponse<Document> response = INDEX.getRange(request);
			if (response.getResults().isEmpty()) {
				break;
			}
			for (Document doc : response) {
				docIds.add(doc.getId());
				count++;
			}
			INDEX.delete(docIds);
		}
		System.out
				.println("Remove " + count + " document from Index success !");

	}

	public static void reindex() {
		int count = 0;
		/*
		 * TubeModel tubeModel = new TubeModel(); tubeModel.setPage(1); while
		 * (true) { tubeModel.setLimit(488); tubeModel.getTubes(false);
		 * List<Tube> list = tubeModel.getListResult(); for (Tube tube : list) {
		 * index(tube); count++; } if (list.size() < 488) { break; }
		 * tubeModel.setPage(tubeModel.getPage() + 1); }
		 * System.out.println("Index " + count +
		 * " document from Tube table success !");
		 */
	}

	@SuppressWarnings("unchecked")
	public static Document.Builder objectToSearchDocument(
			Document.Builder docBuilder, Object obj) {
		for (java.lang.reflect.Field f : obj.getClass().getDeclaredFields()) {
			f.setAccessible(true);
			if (f.getType().getSimpleName().equals("String")) {
				try {
					docBuilder.addField(Field.newBuilder().setName(f.getName())
							.setText((String) f.get(obj)));
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("int")) {
				try {
					docBuilder.addField(Field.newBuilder().setName(f.getName())
							.setNumber(f.getInt(obj)));
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("Date")) {
				try {
					docBuilder.addField(Field
							.newBuilder()
							.setName(f.getName())
							.setDate(
									DateHelper.removeTimeFromDate((Date) f
											.get(obj))));
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("boolean")) {
				try {
					docBuilder.addField(Field.newBuilder().setName(f.getName())
							.setText(((Boolean) f.get(obj)).toString()));
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else if (f.getType().getSimpleName().equals("long")) {
				try {
					docBuilder.addField(Field.newBuilder().setName(f.getName())
							.setNumber(f.getLong(obj)));
				} catch (Exception e) {
					e.printStackTrace();
					docBuilder.addField(Field.newBuilder().setName(f.getName())
							.setNumber(1));
				}
			} else if (f.getType().getSimpleName().equals("List")) {
				try {
					List<String> list = (ArrayList<String>) f.get(obj);
					StringBuilder stringBuilder = new StringBuilder();
					for (String string : list) {
						stringBuilder.append(string);
						stringBuilder.append(",");
					}
					try {
						docBuilder.addField(Field.newBuilder()
								.setName(f.getName())
								.setText(stringBuilder.toString()));
					} catch (Exception e) {

					}
				} catch (Exception e) {

				}
			}
		}
		return docBuilder;
	}

	public static ArticleSearch documentToObjectByReflection(ScoredDocument doc) {
		ArticleSearch obj = new ArticleSearch();
		for (java.lang.reflect.Field f : obj.getClass().getDeclaredFields()) {
			f.setAccessible(true);
			if (f.getType().getSimpleName().equals("String")) {
				try {
					StringBuilder tmpString = new StringBuilder();
					tmpString.append(doc.getOnlyField(f.getName()).getText());
					f.set(obj, tmpString.toString());
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("int")) {
				try {
					f.set(obj, doc.getOnlyField(f.getName()).getNumber()
							.intValue());
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("Date")) {
				try {
					f.set(obj, doc.getOnlyField(f.getName()).getDate());
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("boolean")) {
				try {
					f.set(obj,
							doc.getOnlyField(f.getName()).getText()
									.equals("true") ? true : false);
				} catch (Exception e) {

				}
			} else if (f.getType().getSimpleName().equals("long")) {
				try {
					f.set(obj, doc.getOnlyField(f.getName()).getNumber()
							.longValue());
				} catch (Exception e) {
					try {
						f.set(obj, 1);
					} catch (Exception e2) {

					}
				}
			} else if (f.getType().getSimpleName().equals("List")) {
				try {
					List<String> list = new ArrayList<String>();
					String[] tags = doc.getOnlyField(f.getName()).getText()
							.split(",");
					for (String string : tags) {
						list.add(string);
					}
					f.set(obj, list);
				} catch (Exception e) {

				}
			}
		}
		return obj;
	}
}
